﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Zsg_PeerToPeer
{
    /// <summary>
    /// 打洞服务端，非常的简单，接收两个连接并且转发给对方；
    /// </summary>
    public class ServerListener : IServerListener
    {
        IPEndPoint EndPoint { get; set; }
        //消息委托
        public delegate void EventMsg(object sender, string e);
        public static object obj = new object();
        //通知消息
        public event EventMsg NoticeMsg;
        //接收事件
        public event EventMsg ReceivedMsg;
        /// <summary>
        /// 上次链接的
        /// </summary>
        private Socket Previous;
        public ServerListener(IPEndPoint endpoint)
        {
            this.EndPoint = endpoint;
        }
        private Socket listener;
        public void Start()
        {
            this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            var connectArgs = new SocketAsyncEventArgs();            
            listener.Bind(EndPoint);
            listener.Listen(2);
            EndPoint = (IPEndPoint)listener.LocalEndPoint; 
            connectArgs.Completed += OnAccept;
            //是否同步就完成了，同步完成需要自己触发
            if (!listener.AcceptAsync(connectArgs))
                OnAccept(listener, connectArgs);
        }
        byte[] bytes = new byte[400];
        private void OnAccept(object sender, SocketAsyncEventArgs e)
        {
            Socket socket = null;
            try
            {
                var remoteEndPoint1 = e.AcceptSocket.RemoteEndPoint.ToString();
                NoticeMsg?.Invoke(sender, $"客户端：{remoteEndPoint1}连接上我了！\r\n");
                SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
                readEventArgs.Completed += OnSocketReceived;
                readEventArgs.UserToken = e.AcceptSocket;
                readEventArgs.SetBuffer(bytes, 0, 400);
                if (!e.AcceptSocket.ReceiveAsync(readEventArgs))
                    OnSocketReceived(e.AcceptSocket, readEventArgs);
                lock (obj)
                {
                    socket = e.AcceptSocket;
                    //上次有链接并且链接还“健在”
                    if (Previous == null||! Previous.Connected)
                    {
                        Previous = e.AcceptSocket;
                    }
                    else
                    {
                        //Previous.SendAsync()..?
                        Previous.Send(Encoding.UTF8.GetBytes(remoteEndPoint1 + "_1"));
                        socket.Send(Encoding.UTF8.GetBytes(Previous.RemoteEndPoint.ToString() + "_2"));
                        NoticeMsg?.Invoke(sender, $"已经通知双方！\r\n");
                        Previous = null;
                    }
                } 
               
                e.AcceptSocket = null;
                if (e.SocketError != SocketError.Success)
                    throw new SocketException((int)e.SocketError);
                
                if(!listener.AcceptAsync(e))
                    OnAccept(listener, e);
            }
            catch
            {
                socket?.Close();
        }

        }
        public void Close()
        {
            using (listener)
            {
               // listener.Shutdown(SocketShutdown.Both);
                listener.Close();
            }
            //throw new NotImplementedException();
        }
        /// <summary>
        /// 此处留有一个小BUG，接收的字符串大于400的时候会有问题；可以参考客户端修改
        /// </summary>
        public void OnSocketReceived(object sender, SocketAsyncEventArgs e)
        {            
            Socket socket = e.UserToken as Socket;            
            var remoteEndPoint = socket.RemoteEndPoint.ToString();
            try
            { 
                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    
                    ReceivedMsg?.Invoke(sender, $"收到：{remoteEndPoint}发来信息：{Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred)}\r\n");                 
 
                }
                else
                {
                    socket?.Close();
                    NoticeMsg?.Invoke(sender, $"链接：{remoteEndPoint}释放啦！\r\n");
                    return;
                }
                if (!socket.ReceiveAsync(e))
                    OnSocketReceived(socket, e);
            }
            catch
            {
                socket?.Close();
            }
            
            //{
            //    if (!((Socket)sender).AcceptAsync(e))
            //        OnSocketReceived(sender, e);
            //}
            //catch
            //{
            //    return;
            //}
        }
    }
}
